home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / ue312src.zip / MSWEXEC.C < prev    next >
C/C++ Source or Header  |  1992-10-12  |  15KB  |  484 lines

  1. /* The routines in this file provide support for external program
  2.    execution under the Microsoft Windows environment on an IBM-PC or
  3.    compatible computer.
  4.  
  5.    Must be compiled with Borland C++ 2.0 or MSC 6.0 or later versions
  6.  
  7.    It should not be compiled if the WINDOW_MSWIN symbol is not set */
  8.  
  9. #include    "estruct.h"
  10. #include    <stdio.h>
  11. #include    "eproto.h"
  12. #include    "edef.h"
  13. #include    "elang.h"
  14.  
  15. #include    "mswin.h"
  16.  
  17. #define CMDLENGTH   256+NFILEN
  18.  
  19. /* local data */
  20. #if WINDOW_MSWIN32
  21. static STARTUPINFO suInfo = { 0 };
  22. static char suTitle [] = PROGNAME "'s subshell";
  23. static PROCESS_INFORMATION pInfo = { 0 };
  24. #else
  25. static HWND hPrgWnd;    /* window handle of the external program task */
  26. #endif
  27.  
  28.  
  29. /* HandleTimer: checks the existence of the external program window */
  30. /* ===========                                                      */
  31.  
  32. static void PASCAL  HandleTimer (HWND hDlg)
  33.  
  34. /* This function uses a 200ms timeout to check the existence of the window
  35.    indicated by hPrgWnd. When that window handle becomes invalid, it is
  36.    assumed that the external program has exited and the WAITFORPRG
  37.    dialog box is terminated with a TRUE result. If there is a problem
  38.    setting the timer, the dialog box is terminated with a FALSE result
  39.    after a message box announcing the problem has been displayed. */
  40. {
  41. #if WINDOW_MSWIN32
  42.     /* check for process completion */
  43.     if (WaitForSingleObject(pInfo.hProcess, 0) == WAIT_TIMEOUT) {
  44. #else
  45.     /* look for the program window */
  46.     if (IsWindow (hPrgWnd)) {
  47. #endif
  48.     while (!SetTimer (hDlg, 1, 200, NULL)) {
  49.         /* bad: problem setting the timer */
  50.         if (MessageBox (hDlg, TEXT337, NULL, MB_RETRYCANCEL) == IDCANCEL) {
  51.             /* "cannot monitor external program" */
  52.         EndDialog (hDlg, FALSE);    /* give up! */
  53.         return;
  54.         }
  55.         /* else: attempt a retry */
  56.     }
  57.     }
  58.     else {
  59.     EndDialog (hDlg, TRUE);
  60.     }
  61. } /* HandleTimer */
  62.  
  63. /* WAITFORPRGDlgProc:   dialog proc for WAITFORPRG dialog box */
  64. /* =================                                          */
  65. int EXPORT FAR PASCAL  WAITFORPRGDlgProc (HWND hDlg, UINT wMsg,
  66.                       UINT wParam, LONG lParam)
  67. {
  68.     switch (wMsg) {
  69.     case WM_INITDIALOG:
  70.         SetWindowText (hDlg, PROGNAME);
  71.     HandleTimer (hDlg);
  72.     return TRUE;
  73.     case WM_TIMER:
  74.     HandleTimer (hDlg);
  75.     break;
  76.     case WM_COMMAND:
  77.     if (LOWORD(wParam) == 2) {  /* Cancel */
  78.         KillTimer (hDlg, 1);
  79.         EndDialog (hDlg, FALSE);
  80.     }
  81.     break;
  82.     default:
  83.     return FALSE;
  84.     }
  85.     return FALSE;
  86. } /* WAITFORPRGDlgProc */
  87.  
  88. /* LaunchPrgEnumProc:   used by LaunchPrg */
  89. /* =================                      */
  90. BOOL EXPORT FAR PASCAL LaunchPrgEnumProc (HWND hWnd, LONG lParam)
  91.  
  92. /* this function sets hPrgWnd when it finds a window that matches the
  93.    module instance handle passed in lParam */
  94. {
  95. #if !WINDOW_MSWIN32
  96.     if (GetWindowWord (hWnd, GWW_HINSTANCE) == LOWORD(lParam)) {
  97.     hPrgWnd = hWnd;
  98.     return FALSE;   /* found it, stop enumerating */
  99.     }
  100. #endif
  101.     return TRUE;
  102. } /* LaunchPrgEnumProc */
  103.  
  104. /* LaunchPrg:   launches and monitors an external program  */
  105. /* =========                                               */
  106.  
  107. static BOOL PASCAL  LaunchPrg (char *Cmd, BOOL DOSApp,
  108.                                char *InFile, char *OutFile)
  109.  
  110. /* Returns TRUE if all went well, FALSE if wait cancelled and FAILED if
  111.    failed to launch.
  112.  
  113.    Cmd is the command string to launch.
  114.  
  115.    DOSApp is TRUE if the external program is a DOS program to be run
  116.    under a DOS shell. If DOSApp is FALSE, the program is launched
  117.    directly as a Windows application. In that case, the InFile parameter
  118.    is ignored, and the value of the OutFile parameter is used only to
  119.    determine if the program should be monitored. the text of the string
  120.    referenced by OutFile is irrelevant.
  121.  
  122.    InFile is the name of the file to pipe into stdin (if NULL, nothing
  123.    is piped in)
  124.  
  125.    OutFile is the name of the file where stdout is expected to be
  126.    redirected. If it is NULL or an empty string, stdout is not redirected
  127.  
  128.    If Outfile is NULL, LaunchPrg returns immediately after starting the
  129.    DOS box.
  130.  
  131.    If OutFile is not NULL, the external program is monitored.
  132.    LaunchPrg returns only when the external program has terminated or
  133.    the user has cancelled the wait (in which case LaunchPrg returns
  134.    FALSE). */
  135. {
  136.     char    FullCmd [CMDLENGTH];
  137.     HANDLE  hModule;
  138.     int     nCmdShow;
  139.     BOOL    Synchronize;
  140. #if !WINDOW_MSWIN32
  141.     FARPROC ProcInstance;
  142. #endif
  143.  
  144.     if (OutFile) {
  145.         Synchronize = TRUE;
  146.         if (*OutFile == '\0') OutFile = NULL; /* stop worrying about that
  147.                                                  empty string */
  148.     }
  149.     else Synchronize = FALSE;
  150.  
  151.     if (SetWorkingDir () != 0) {
  152.         mlwrite (TEXT334);  /* "[No such directory]" */
  153.         return FALSE;
  154.     }
  155.     if (DOSApp) {
  156. #if WINDOW_MSWIN32
  157.         GetProfileString (ProgName, "Shell", "cmd.exe", FullCmd, CMDLENGTH);
  158.     /* the Shell profile string should contain the name of the shell
  159.            to be used for pipe-command, filter buffer, shell-command and
  160.            i-shell. The ShellExecOption profile string should contain
  161.            the option flags that cause the execution under that shell of
  162.            a single command (the text of which is appended to the profile
  163.            string) so that the shell terminates with that command. */
  164.     if (Cmd) {
  165.         char ExecOption [10];
  166.         
  167.             GetProfileString (ProgName, "ShellExecOption", " /c ",
  168.                               ExecOption, 10);
  169.         if ((strlen (FullCmd) + strlen (ExecOption) + strlen (Cmd)) >=
  170.                 CMDLENGTH) return FALSE;
  171.         strcat (FullCmd, ExecOption);
  172.         strcat (FullCmd, Cmd);
  173.     }
  174. #else
  175.         if (Synchronize || !Cmd) {
  176.         GetProfileString (ProgName, "DOSExec", "",
  177.                   FullCmd, CMDLENGTH);
  178.             if (FullCmd[0] == '\0') {   /* try to find it on the "path" */
  179.                 char    *s;
  180.  
  181.                 if ((s = flook ("DOSEXEC.PIF", TRUE)) != NULL) {
  182.                     strcpy (FullCmd, s);
  183.                 }
  184.             }
  185.         }
  186.     else FullCmd[0] = '\0';
  187.     if (FullCmd[0] == '\0') {
  188.         GetProfileString (ProgName, "DOSBox", "",
  189.                           FullCmd, CMDLENGTH);
  190.             if (FullCmd[0] == '\0') {   /* try to find it on the "path" */
  191.                 char    *s;
  192.  
  193.                 if ((s = flook ("DOSBOX.PIF", TRUE)) != NULL) {
  194.                     strcpy (FullCmd, s);
  195.                 }
  196.                 else strcpy (FullCmd, "command.com");
  197.             }
  198.         }
  199.     /* the DOSBox profileString should be the name of a PIF file for
  200.        command.com that specifies no arguments and no starting dir.
  201.        The DOSExec should be similar but specify "Close window on
  202.        exit" so that synchronization can work */
  203.     if (Cmd) {
  204.         if ((strlen (FullCmd) + strlen (Cmd) + 4) >=
  205.                 CMDLENGTH) return FALSE;
  206.         strcat (FullCmd, " /c ");
  207.         strcat (FullCmd, Cmd);
  208.     }
  209. #endif
  210.     if (InFile) {
  211.         if ((strlen (FullCmd) + strlen (InFile) + 2) >=
  212.                 CMDLENGTH) return FALSE;
  213.         strcat (FullCmd, " <");
  214.         strcat (FullCmd, InFile);
  215.     }
  216.     if (OutFile) {
  217.         if ((strlen (FullCmd) + strlen (OutFile) + 2) >=
  218.                 CMDLENGTH) return FALSE;
  219.         strcat (FullCmd, " >");
  220.         strcat (FullCmd, OutFile);
  221.     }
  222.     }
  223. #if WINDOW_MSWIN32
  224.     /* set the startup window size */
  225.     suInfo.cb = sizeof(STARTUPINFO);
  226.     if (DOSApp && Cmd) suInfo.lpTitle = suTitle;
  227.     suInfo.wShowWindow = (DOSApp && Synchronize) ? SW_SHOWMINIMIZED :
  228.                                                    SW_SHOWNORMAL;
  229.     suInfo.dwFlags     = STARTF_USESHOWWINDOW;
  230.  
  231.     /* start the process and get a handle on it */
  232.     if (CreateProcess (NULL, DOSApp ? FullCmd : Cmd, NULL, NULL,
  233.                        DETACHED_PROCESS, 
  234.                        FALSE, NULL, NULL, &suInfo, &pInfo)) {
  235.         int Result;
  236.  
  237.         if (Synchronize) {
  238.             /* put up a dialog box to wait for termination */
  239.             Result = DialogBox (hEmacsInstance, "WAITFORPRG",
  240.                                 hFrameWnd, WAITFORPRGDlgProc);
  241.     }
  242.         else {
  243.             /* no need to synchronize */
  244.             Result = TRUE;
  245.     }
  246.         CloseHandle(pInfo.hThread);
  247.         CloseHandle(pInfo.hProcess);
  248.  
  249.         return Result;
  250.     } else return FALSE;
  251. #else
  252.     if (Win386Enhanced) {
  253.         if (DOSApp && Synchronize) nCmdShow = SW_SHOWMINIMIZED;
  254.         else nCmdShow = SW_SHOWNORMAL;
  255.     }
  256.     else nCmdShow = SW_SHOWNORMAL;
  257.  
  258.     hModule = WinExec (DOSApp ? FullCmd : Cmd, nCmdShow);
  259.         /* here we GOoooo */
  260.  
  261.     if (hModule < 32) {
  262.         mlwrite (TEXT3);    /* "[Execution failed]" */
  263.         return FAILED;
  264.     }
  265.     if (!Synchronize) return TRUE;  /* no synchronization */
  266.     hPrgWnd = 0;
  267.     ProcInstance = MakeProcInstance ((FARPROC)LaunchPrgEnumProc,
  268.                                      hEmacsInstance);
  269.     EnumWindows (ProcInstance, (DWORD)hModule);
  270.     FreeProcInstance (ProcInstance);
  271.     if (hPrgWnd != 0) {
  272.     /*-put up a dialog box to wait for the external program termination */
  273.     int     Result;
  274.  
  275.     ProcInstance = MakeProcInstance ((FARPROC)WAITFORPRGDlgProc,
  276.                                          hEmacsInstance);
  277.     Result = DialogBox (hEmacsInstance, "WAITFORPRG",
  278.                 hFrameWnd, ProcInstance);
  279.     FreeProcInstance (ProcInstance);
  280.     return Result;
  281.     }
  282.     else return TRUE;   /* we assume it has zipped past us! */
  283. #endif
  284. } /* LaunchPrg */
  285.  
  286. /* spawncli:    launch DOS shell. Bound to ^X-C */
  287. /* ========                                     */
  288.  
  289. PASCAL spawncli (int f, int n)
  290. {
  291.     /*-don't allow this command if restricted */
  292.     if (restflag) return resterr();
  293.  
  294.     return LaunchPrg (NULL, TRUE, NULL, NULL);
  295. } /* spawncli */
  296.  
  297. /* spawn:   run a one-liner in a DOS box. Bound to ^X-! */
  298. /* =====                                                */
  299.  
  300. PASCAL spawn (int f, int n)
  301. {
  302.     char    Line[NLINE];
  303.     int     Result;
  304.     char    *SynchOption;
  305.     static char empty[] = "";
  306.  
  307.     /*-don't allow this command if restricted */
  308.     if (restflag) return resterr();
  309.  
  310.     if ((Result = mlreply ("!", Line, NLINE)) != TRUE) return Result;
  311.     if (f) SynchOption = &empty[0];
  312.     else SynchOption = NULL;
  313.     return LaunchPrg (Line, TRUE, NULL, SynchOption);
  314. } /* spawn */
  315.  
  316. /* execprg: run another program with arguments. Bound to ^X-$ */
  317. /* =======                                                    */
  318.  
  319. PASCAL execprg (int f, int n)
  320. {
  321.     char    Line[NLINE];
  322.     int     Result;
  323.     char    *SynchOption;
  324.  
  325.     /*-don't allow this command if restricted */
  326.     if (restflag) return resterr();
  327.  
  328.     /*-get the program command line */
  329.     if (mlreply ("$", Line, NLINE) != TRUE) return FALSE;
  330.  
  331.     if (f) SynchOption = &Line[0];  /* any not NULL will do */
  332.     else SynchOption = NULL;
  333.     Result = LaunchPrg (Line, FALSE, NULL, SynchOption);
  334.     if (Result == FAILED) {
  335.         mlwrite (TEXT3);    /* "[Execution failed]" */
  336.     }
  337.     return Result;
  338. } /* execprg */
  339.  
  340. /* pipecmd: pipe a one-liner into a window. Bound to ^X-@ */
  341. /* =======                                                */
  342.  
  343. PASCAL pipecmd (int f, int n)
  344.  
  345. /* this function fills a buffer named "command" with the output of the
  346.    DOS one-liner. If the command buffer already exist, it is overwritten
  347.    only if it has not been changed */
  348. {
  349.     char    Line[NLINE];
  350.     char    OutFile[NFILEN];
  351.     static  char bname[] = "command";
  352.     BUFFER  *bp;
  353.     WINDOW  *wp;
  354.     int     Result;
  355.     int     bmode;
  356.     char    bflag;
  357. #if WINDOW_MSWIN32
  358.     char    TempDir[NFILEN] = "\\";
  359. #endif
  360.  
  361.     /*-don't allow this command if restricted */
  362.     if (restflag) return resterr();
  363.  
  364.     /*-get the command to pipe-in */
  365.     if (mlreply ("@", Line, NLINE) != TRUE) return FALSE;
  366.  
  367.     /*-find the "command" buffer */
  368.     if ((bp = bfind (bname, FALSE, 0)) != NULL) {
  369.     /*-make sure the contents can safely be blown away */
  370.     if (bp->b_flag & BFCHG) {
  371.         if (mlyesno (TEXT32) != TRUE) return FALSE;
  372.         /* discard changes */
  373.     }
  374.     }
  375.     else if ((bp = bfind (bname, TRUE, 0)) == NULL) {
  376.     mlwrite (TEXT137);
  377.         /* cannot create buffer */
  378.         return FALSE;
  379.     }
  380. #if WINDOW_MSWIN32
  381.     GetTempPath (NFILEN, TempDir);
  382.     GetTempFileName (TempDir, "UE", 0, OutFile);
  383. #else
  384.     GetTempFileName (0, "UE", 0, OutFile);
  385. #endif
  386.     Result = LaunchPrg (Line, TRUE, NULL, OutFile);
  387.     if (Result == FAILED) {
  388.     mlwrite (TEXT3);
  389.         /* [execution failed] */
  390.     unlink (OutFile);
  391.     }
  392.     else {
  393.         if (Result == TRUE) {
  394.         BUFFER  *temp_bp;
  395.  
  396.         temp_bp = curbp;
  397.         swbuffer (bp);          /* make this buffer the current one */
  398.         bmode = bp->b_mode;
  399.         bp->b_mode &= ~MDVIEW;
  400.         bflag = bp->b_flag;
  401.         bp->b_flag &= ~BFCHG;
  402.         Result = readin (OutFile, FALSE);
  403.         bp->b_fname[0] = '\0';  /* clear file name */
  404.         if (Result == TRUE) {
  405.         bp->b_mode |= MDVIEW;   /* force VIEW mode */
  406.         lchange (WFMODE);       /* update all relevant mode lines */
  407.         bp->b_flag &= ~BFCHG;   /* remove by-product BFCHG flag */
  408.         }
  409.         else {
  410.         bp->b_mode = bmode;     /* restore mode */
  411.             bp->b_flag = bflag;
  412.         swbuffer (temp_bp);
  413.         }
  414.         unlink (OutFile);
  415.         /* note that the file is not deleted if the wait was cancelled */
  416.     }
  417.     }
  418.     return Result;
  419. } /* pipecmd */
  420.  
  421. /* filter:  filter a buffer through a DOS box. Bound to ^X-# */
  422. /* ======                                                    */
  423.  
  424. PASCAL filter (int f, int n)
  425. {
  426.     char    Line[NLINE];
  427.     char    InFile[NFILEN];
  428.     char    OutFile[NFILEN];
  429.     char    fname[NFILEN];
  430.     BUFFER  *bp;
  431.     WINDOW  *wp;
  432.     int     Result;
  433. #if WINDOW_MSWIN32
  434.     char    TempDir[NFILEN] = "\\";
  435. #endif
  436.  
  437.     /*-don't allow this command if restricted */
  438.     if (restflag) return resterr();
  439.  
  440.     /*-get the filter command line */
  441.     if (mlreply ("#", Line, NLINE) != TRUE) return FALSE;
  442.  
  443.     bp = curbp;
  444.     strcpy (fname, bp->b_fname);
  445. #if WINDOW_MSWIN32
  446.     GetTempPath (NFILEN, TempDir);
  447.     GetTempFileName (TempDir, "UE", 0, InFile);
  448. #else
  449.     GetTempFileName (0, "UE", 0, InFile);
  450. #endif
  451.     Result = writeout (InFile, "w");
  452.     if (Result != TRUE) {
  453.     mlwrite (TEXT2);
  454.         /* cannot write filter file */
  455.     }
  456.     else {
  457. #if WINDOW_MSWIN32
  458.         GetTempFileName (TempDir, "UE", 0, OutFile);
  459. #else
  460.         GetTempFileName (0, "UE", 0, OutFile);
  461. #endif
  462.     Result = LaunchPrg (Line, TRUE, InFile, OutFile);
  463.         if (Result == FAILED) {
  464.         mlwrite (TEXT3);
  465.         /* [execution failed] */
  466.             unlink (OutFile);
  467.             unlink (InFile);
  468.         }
  469.     else {
  470.             if (Result == TRUE) {
  471.         Result = readin (OutFile, FALSE);
  472.         unlink (OutFile);
  473.         unlink (InFile);
  474.         }
  475.         /* note that he files are not deleted if the wait was cancelled */
  476.         if (Result == TRUE) {
  477.         lchange (WFMODE);   /* update all relevant mode lines */
  478.         }
  479.     }
  480.     }
  481.     strcpy (bp->b_fname, fname);    /* restore original file name */
  482.     return Result;
  483. } /* filter */
  484.